

/* main is just code from class with a few changes $$ PsyLL42 $$
*/
#include "AirHog.h"


//for testing
#define FOUROHFOUR "HTTP/1.0 404 Not Found"
#define TWO	 "HTTP/1.1 200 OK"
#define MAXGET	2049
#define REQ_LEN 1024
#define PATH_LEN 256

//name for a html 404 error page
#define FOUR_O_FOURHTML "./404.html"

#define INDEXHTML "/index.html"



char *ROOTDIR;

void handler(int sig)
{

	pid_t pid;
	int status;
 
	// Find out which signal we're handling
	switch (sig) 
	{
		case SIGCHLD:

			while ( (pid = waitpid(-1, &status, WNOHANG)) > 0);
			//pid = wait();
			//fprintf(stderr, "exited %d\n",pid );
			break;
		case SIGINT:
			fprintf(stderr,"Caught SIGINT, exiting now\n");			
			exit(1);
			break; //you will never get me
	}

	return;
}


int main(int argc, char *argv[])
{
	int sockfd, newsockfd, portno, clilen, pid;
	int optval = 1;
	char* address;

	struct sockaddr_in serv_addr, cli_addr;
	struct sigaction act;

	sigemptyset (&act.sa_mask);
	act.sa_handler = &handler;
	act.sa_flags |= SA_RESTART;	
	
	if(sigaction(SIGCHLD, &act, NULL))
	{
		error("Error on SIGCHLD");
	}
	if(sigaction(SIGINT, &act,NULL))
	{
		error("ERROR on SIGINT");
	}

	switch(argc)
	{
		case 2:
			portno = atoi(argv[1]);

			break;
		case 3:
			portno = atoi(argv[1]);
			address = argv[2];
			break;
		case 4:
			portno = atoi(argv[1]);
			address = argv[2];
			ROOTDIR = strncpy(malloc(sizeof(char)*strlen(argv[3])+1),argv[3],strlen(argv[3]+1));
			break;
		default:
			fprintf(stderr, "Unknown args\n");
			fprintf(stderr,"No address or port provided using 127.0.0.1:8080 with the current directory as the root\n");
			portno = 8080;
			address = "127.0.0.1";
			ROOTDIR = ".";
			break;
	}



	if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
	{ 
		error("ERROR opening socket");
	}

	//setting it so I can rebind to a socket address 
	//this means no Address already in use error
	if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(int)))
	{
		error("ERROR on setsockopt socket");
	}

	memset((char *) &serv_addr,0, sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = inet_addr(address);
	serv_addr.sin_port = htons(portno);

	if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
	{
		error("ERROR on binding");
	}
  
	listen(sockfd,5);
	clilen = sizeof(cli_addr);
	while (1) 
	{
		newsockfd = accept(sockfd,(struct sockaddr *) &cli_addr, &clilen);
		if (newsockfd < 0)
		{ 
			error("ERROR on accept");
		}

		pid = fork();
	
		if (pid < 0)
		{
			error("ERROR on fork");
		}
		if (pid == 0)
		{
			respond(newsockfd);
		}
		else 
			close(newsockfd);
	} 

		return 0; 
}


void respond (int connectionfd)
{
	struct stat st;
	Header response_msg;
	char buff[MAXGET];
	char request[REQ_LEN];
	char *path;
	char *root;
	int fd;
	size_t input_size=0;
	int length,i;
	char ch[2];

	memset(buff,0,MAXGET);
	memset(request,0,REQ_LEN);
	memset(ch,0,2);



	i=0;
	int flag =0;
	fflush(stderr);

	//reading in one byte at a time to get the request
	while(read(connectionfd, &ch,2)==2 && i<REQ_LEN-1  && (request[i-1]+request[i-2]+ch[0]+ch[1])!=46)
	{
			request[i++] = ch[0];
			request[i++] = ch[1];
	}
	
	fprintf(stderr, "REQUEST:%s\n", request);
	
	if(strncmp(request,"GET",3))
	{
		response_msg.response ="HTTP/1.1 501 Method Not Implemented";
		response_msg.len=0;
		make_response(buff,&response_msg);
	}
	else
	{

		strtok(request," ");
		path = strtok(NULL," ");

		fprintf(stderr, "REQUEST:%s\n", request);
		
		if(strncmp(path,"/",2)==0)
		{
			path=INDEXHTML;
		}
		root = strncat(malloc(sizeof(char)*(strlen(path)+strlen(ROOTDIR)+2)),ROOTDIR,strlen(ROOTDIR));
		path = strncat(root,path,strlen(path)+strlen(ROOTDIR)+1);
		fprintf(stderr, "%s\n",path );
		

		if((fd=open(path,O_RDONLY))<0)
		{
			
			fd=open(FOUR_O_FOURHTML,O_RDONLY);
			
			if(stat(FOUR_O_FOURHTML, &st))
			{
	    	error("ERROR: On stat");
			}
			else
			{
				fprintf(stderr, "%s\n","404" );
				response_msg.len = st.st_size;
				response_msg.response = "HTTP/1.1 404 Not Found";
			}
		}
		else
		{
			if (stat(path, &st))
			{
	    	error("ERROR: On stat");
			}
			else
			{
				response_msg.len = st.st_size;
				response_msg.response =TWO;
			}
		}

		fprintf(stderr, "%s\n",response_msg.response);
		make_response(buff,&response_msg);
	}

	if(write(connectionfd,buff,strlen(buff))<0)
	{
		error("ERROR on write");
	}

	while((length=read(fd,&buff[0],256))>0)
	{
		write(connectionfd,&buff[0],length);
	}
	
	free(root);
	close(fd);
	

	close(connectionfd);
	exit(0);
}

char* make_response(char *response, Header* info )
{
	if(sprintf(response,"%s\nAccept-Ranges: bytes\nContent-Length: %lu\nConnection: close\nContent-Type: text/html\n\n",info->response,info->len)<0)
		{
			error("ERROR on sprintf");
		}
	return response;
}


void error(char *msg)
{
	perror(msg);
	exit(1);
}


